#include <boost/scoped_array.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/function.hpp>
#include "Td_object.h"
#include "animation.h"
#include <boost/random.hpp>
#include <list>
//#undef check
//#include <boost/lambda/lambda.hpp>


namespace gauss_random {	
	
	typedef boost::minstd_rand base_generator_type;
	static base_generator_type generator(time(NULL));
	static boost::uniform_real<> uni_dist(0,1);
	static boost::variate_generator<base_generator_type, boost::uniform_real<> > uni(generator, uni_dist);
	template <typename result_type>
	result_type get_normal_distribution(result_type mean = 0, result_type sigma = 1)
	{		
		boost::normal_distribution<result_type> normal_distribution_generator(mean, sigma);
		return normal_distribution_generator(uni);
	}
	
	template <typename result_type>
	result_type get_uniform(result_type range)
	{
		return range * uni.operator()();
	}
};


class birdFlyingAnimation : public AnimationBase{
public:
	birdFlyingAnimation(const char * file_name, int row, int col, float_t size, point2d_t pos, point2d_t vel) : AnimationBase(file_name, row, col) , m_frame(0){
		float_t width = size * m_tex.getWidth() / m_col;
		float_t height = size * m_tex.getHeight() / m_row;
		width /= 2.0;
		height /= 2.0;
		m_verts[0] = -width, -height;
		m_verts[1] = -width, height;
		m_verts[2] = width, height;
		m_verts[3] = width, -height;
		m_verts[0] += pos;
		m_verts[1] += pos;
		m_verts[2] += pos;
		m_verts[3] += pos;
		m_vel = vel;
		m_pos = pos;
	}
	~birdFlyingAnimation() {}
	virtual void getFrameTex() {
		int index = m_frame/2;
		glTexCoordPointer(2, GL_FLOAT, 0, &m_coords[index%m_count]);
		m_frame++;
	}
	void draw()
	{
		point2d_t vel(gauss_random::get_normal_distribution<float_t>(m_vel[0], 0.3), gauss_random::get_normal_distribution<float_t>(0, 1));
		m_pos += vel;
		m_verts[0] += vel;
		m_verts[1] += vel;
		m_verts[2] += vel;
		m_verts[3] += vel;
		
		glEnable(GL_TEXTURE_2D);
#ifdef WIN32
		glBindTexture(GL_TEXTURE_2D, m_txtPtr->texID);
#else
		glBindTexture(GL_TEXTURE_2D, m_tex.getName());
#endif
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glVertexPointer(2, GL_FLOAT, 0, &m_verts);
		getFrameTex();
		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
	}
	
	virtual void reset() {m_frame = 0;}
	
	virtual bool runningOut() {
		return !(m_pos[0] >= 0 && m_pos[0] <= SCREEN_WIDTH);
	}
public:
	point2d_t m_pos;
protected:
	vert_t m_verts;
	point2d_t m_vel;	
	int m_frame;
};

template <typename T>
void deleteThis(T *p)
{
	delete p;
}
namespace {
	const int BIRD_NUM = 6;
	typedef std::list<boost::shared_ptr<birdFlyingAnimation> > birds_t;
	birdFlyingAnimation *getNewBird(bool isCenter = true) {
		float_t size = 0.1f + gauss_random::get_normal_distribution<float_t>(0.6, 0.2);
		point2d_t pos;
		bool direction2right = gauss_random::get_uniform<float_t>(1) > 0.5;
		if (isCenter) {
			pos = gauss_random::get_uniform<float_t>(480), gauss_random::get_normal_distribution<float_t>(220, 40);
		}
		else {
			if (direction2right)
				pos = gauss_random::get_normal_distribution<float_t>(0, 1), gauss_random::get_normal_distribution<float_t>(220, 40);
			else
				pos = gauss_random::get_normal_distribution<float_t>(SCREEN_WIDTH, 1), gauss_random::get_normal_distribution<float_t>(220, 40);
		}
		point2d_t vel(gauss_random::get_normal_distribution<float_t>(size/0.6f, 0.3), gauss_random::get_normal_distribution<float_t>(0, 1));
		if (!direction2right) vel[0] = -vel[0];
		return new birdFlyingAnimation("flying_bird.png2", 2, 5, size, pos, vel);
	}
	void update(birds_t *birds)
	{
		for (birds_t::iterator iter = birds->begin(); iter != birds->end();) {
			(*iter)->draw();
			if ((*iter)->runningOut()) {
				iter = birds->erase(iter);
			}
			else {
				iter++;
			}
		}
		if (gauss_random::get_uniform<float_t>(1) < 0.01) {
			birds_t::value_type bird(getNewBird(false));
			birds->push_back(bird);
		}
	}
};

void setSceneAnimation(SceneAnimation_delegate_t &sceneAnimation, const std::string &sceneName)
{
	if ( NULL != sceneAnimation._free) sceneAnimation._free();
	if (std::string::npos != sceneName.find("matou")) {
		int num = 1 +  gauss_random::get_uniform<int>(BIRD_NUM);
		birds_t * birds = new birds_t;
		for (int i = 0; i < num ; i++) {
			birds_t::value_type bird(getNewBird());
			birds->push_back(bird);
		}		
		sceneAnimation._free = boost::bind(&deleteThis<birds_t>, birds);		
		sceneAnimation._update = boost::bind(update, birds);		
	}
	else {
		sceneAnimation._free = NULL;		
		sceneAnimation._update = NULL;		
	}
}
